package org.mg.frontend.bean;


import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.Cookie;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

/**
 * Class containing <b>JSF</b> utility methods.
 */
public final class BeanUtils {

    /**
     * Path to the resource bundle name used by
     * {@link org.mg.frontend.bean.BeanUtils#addMessage(String, javax.faces.application.FacesMessage.Severity, String, Object...)}
     */
    private static final String RESOURCE_BUNDLE_BASE_NAME = "org.curs.resources.messages";

    public static ExternalContext getExternalContext() {
       return FacesContext.getCurrentInstance().getExternalContext();
    }

    /**
     * Checks if current request is a Post Back request (i.e. comming back from a post)
     * @return true if request is a postback request, false otherwise
     */
    public static boolean isPostBack() {
        return FacesContext.getCurrentInstance().isPostback();
    }

    /**
     * Gets the current request view locale
     *
     * @return the current view locale
     */
    public static Locale getViewLocale() {
        return FacesContext.getCurrentInstance().getViewRoot().getLocale();
    }

    /**
     * Sets the current request view locale
     * <p>Useful for setting the locale of the current PostBack request</p>
     *
     * @param locale the locale to be set
     */
    public static void setViewLocale(Locale locale) {
        FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
    }

    /**
     * Gets the request parameter specified by a key
     *
     * @param key the request parameter key
     * @return the request paramtere value
     */
    public static String getRequestParam(String key) {
        return BeanUtils.getExternalContext().getRequestParameterMap().get(key);
    }

    /**
     * Gets a cookie value from the cookie map
     *
     * @param name a {@code String} representing the name of the cookie
     * @return {@code String} - the cookie value
     */
    public static String getCookieValue(String name) {
        Cookie cookie = (Cookie) getExternalContext().getRequestCookieMap().get(name);
        if (cookie != null) {
            return cookie.getValue();
        }
        return null;
    }

    /**
     * Saves a cookie to the cookie map
     *
     * @param name the cookie name
     * @param value the cookie value
     */
    public static void setCookie(String name, String value) {
        getExternalContext().addResponseCookie(name, value, null);
    }

    /**
     * Adds an object to flash scope map
     *
     * @param key the key of the object
     * @param value the {@code Object} value
     */
    public static void addToFlash(String key, Object value) {
        getExternalContext().getFlash().put(key, value);
    }

    /**
     * Gets an object from the flash scope map
     *
     * @param key the key of the object to get
     * @return the {@code Object} value, or {@code null} if a map entry for the specified key does not exist
     */
    public static Object getFromFlash(String key) {
        return getExternalContext().getFlash().get(key);
    }

    /**
     * Adds a global localized <b>Info</b> message to FacesContext's current PostBack
     *
     * @param msgKey the key of the message
     * @param args the optional arguments of the message - in case it is parametrized
     * @see org.mg.frontend.bean.BeanUtils#addMessage(String, javax.faces.application.FacesMessage.Severity, String, Object...)
     */
    public static void addInfoMessage(String msgKey, Object... args) {
        addMessage(null, FacesMessage.SEVERITY_INFO, msgKey, args);
    }

    /**
     * Adds a global localized <b>Error</b> message to FacesContext's current PostBack
     *
     * @param msgKey the key of the message
     * @param args the optional arguments of the message - in case it is parametrized
     * @see org.mg.frontend.bean.BeanUtils#addMessage(String, javax.faces.application.FacesMessage.Severity, String, Object...)
     */
    public static void addErrorMessage(String msgKey, Object... args) {
        addMessage(null, FacesMessage.SEVERITY_ERROR, msgKey, args);
    }

    /**
     * Adds a localized message to FacesContext's current PostBack
     *
     * @param clientId the client Id this message should be associated with or {@code null} for global message
     * @param severity the severity of the message as provided by {@code FacesMessage.Severity}
     * @param msgKey the key of the message
     * @param arguments the arguments (if any) of the message - in case message is parametrized
     */
    public static void addMessage(String clientId, FacesMessage.Severity severity, String msgKey, Object... arguments) {
        FacesContext.getCurrentInstance().addMessage(clientId, getMessage(severity, msgKey, arguments));
    }

    /**
     * Gets a message by key and optional arguments
     *
     * @param severity the severity of the message as specified in {@link javax.faces.application.FacesMessage.Severity}
     * @param msgKey the key of the message
     * @param arguments the optional arguments of the message
     * @return the {@link javax.faces.application.FacesMessage} obtained from severity, key and arguments
     */
    public static FacesMessage getMessage(FacesMessage.Severity severity, String msgKey, Object... arguments){
        ResourceBundle bundle = ResourceBundle.getBundle(RESOURCE_BUNDLE_BASE_NAME, getViewLocale());

        String msg = bundle.getString(msgKey);
        String formattedMsg = MessageFormat.format(msg, arguments);

        return new FacesMessage(severity, formattedMsg, formattedMsg);
    }
}
